package cn.xiaobai.service.impl.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.xiaobai.service.DateAnalyzeService;
import cn.xioabai.common.utility.IOUtils;
import cn.xioabai.common.utility.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.nio.file.Paths;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Author yangdaji
 * @Date 2023/8/13
 * @PackageName cn.xiaobai.service.impl.impl
 * @ClassName DateAnalyzeServiceImpl
 */
@Slf4j
@Service
public class DateAnalyzeServiceImpl implements DateAnalyzeService {


    /**
     * 年映射表,key: 年份, value: key:日期,value: 节假日状态,1:休息日,2: 节假日
     */
    private static final Map<String, Map<String, Integer>> YEAR_DAY_TO_HOLIDAY_STATE_MAP = new HashMap<>(6);

    private static final String PATTER1 = "yyyy-MM-dd";
    private static final String PATTER2 = "yyyyMMdd";

    /**
     * 文件路径
     */
    @Value("${template.path: ./data}")
    private String filePath;
    /**
     * 文件模板
     */
    @Value("${template.name: _data.json}")
    private String template;

    private DateTime dateTime;

    /**
     * 年份
     */
    private String year;

    /**
     * 日期, 格式: mm-dd, mmdd
     */
    private String dayDate;

    @PostConstruct
    public void initDate() {
        log.info("启动初始化当年的节假日信息");
        String string = DateUtil.now().toString();
        checkDateValidity(string);
        holidayJsonReader();
    }

    @Override
    public Integer queryDateHoliday(String day) {
        // 校验, 年份
        Boolean dateValidity = checkDateValidity(day);
        if (!dateValidity) {
            return -1;
        }

        Integer weekend = isWeekend();
        // 查看是否加载年份信息
        Integer state;
        if (YEAR_DAY_TO_HOLIDAY_STATE_MAP.containsKey(year)) {
            state = getState();
        } else {
            // 没有该年份的信息,则进行加载
            log.info("未检测到该年份的信息, 加载该年份信息");
            holidayJsonReader();
            state = getState();
        }
        // 如果是节假日则返回, 否则判断是否为休息日,否则是工作日
        return state > weekend || state == -2 ? state : weekend;

    }

    private Integer getState() {
        Map<String, Integer> dayToHolidayStateMap = YEAR_DAY_TO_HOLIDAY_STATE_MAP.getOrDefault(year, null);
        // 查看是否包含对应的节假日, 包含则返回对应状态, 否则为工作日
        if (Objects.isNull(dayToHolidayStateMap)) {
            // 为超前年份, 返回-2
            return -2;
        } else if (dayToHolidayStateMap.containsKey(dayDate)) {
            return dayToHolidayStateMap.get(dayDate);
        }
        return 0;
    }


    @Override
    public void holidayJsonReader() {
        boolean yearAhead = DateTime.now().year() < Integer.parseInt(year);
        if (yearAhead) {
            // 超前年份, 对应的数据文件读取为null
            YEAR_DAY_TO_HOLIDAY_STATE_MAP.put(year, null);
        } else {
            // 启动时进行加载一次, 后续按需加载
            File file = Paths.get(filePath, year + template).toFile();
            String readYearFile = IOUtils.readFileToString(file);
            Map<String, Integer> dayToHolidayStateMap = JsonUtils.readValue(readYearFile,
                    new TypeReference<Map<String, Integer>>() {
                    });
            // 如果目标文件不存在, 可能系统没有录入, 或者文件读取位置有问题
            YEAR_DAY_TO_HOLIDAY_STATE_MAP.put(year, dayToHolidayStateMap);
        }
    }

    @Override
    public Boolean checkDateValidity(String day) {
        // 检查日期是否属于合法日期
        boolean isValidity = false;
        try {
            dateTime = DateUtil.parse(day, PATTER1);
            isValidity = true;
        } catch (Exception e) {
            try {
                dateTime = DateUtil.parse(day, PATTER2);
                isValidity = true;
            } catch (Exception ex) {
                log.info("校验日期格式: {} {},失败: {}", PATTER1, PATTER2, e.getMessage());
            }
        }
        if (isValidity) {
            // 转换为 yyyyMMdd 格式
            String dateStr = DateUtil.format(new Date(dateTime.getTime()), PATTER2);
            year = Integer.toString(dateTime.year());
            dayDate = dateStr.substring(year.length());
        }
        return isValidity;
    }

    @Override
    public Integer isWeekend() {
        int week = dateTime.dayOfWeek();
        // 1: 周日, 7: 周六
        return week == 1 || week == 7 ? 1 : 0;
    }
}
